﻿#region

using System;
using System.Collections.Generic;
using System.IO;
using MediaSage.Lib.Configuration;
using MediaSage.Lib.Database;

#endregion

namespace MediaSage.Lib.Utilities
{
    #region Enumerations

    ///<summary>
    ///    Types of merges
    ///
    ///    OVERWRITE               - This will replace destination with source
    ///    WRITE_IF_LARGER         - This will replace fields with the source, if it contains more data
    ///    WRITE_IF_NULL_OR_EMPTY  - This will replace fields if they are null, or contain no data
    ///    COPY_NEW                - This will only add new items if there is no data, this will also add new records to lists
    ///</summary>
    public enum MediaMergeType
    {
        OVERWRITE,
        WRITE_IF_LARGER,
        WRITE_ONLY_ON_NULL_OR_EMPTY,
        COPY_NEW
    }

    #endregion Enumerations

    /// <summary>
    ///     Various methods for dealing with media objects
    /// </summary>
    public static class MediaUtil
    {
        #region Methods

        public static EpisodeEntity MergeEpisodeEntity(EpisodeEntity Source, EpisodeEntity Destination,
                                                       MediaMergeType WriteMethod, bool MergeOnPersonName)
        {
            if (Destination == null || WriteMethod == MediaMergeType.OVERWRITE)
            {
                return Source;
            }
            if (Source == null)
            {
                return Destination;
            }

            var MergedEntity = new EpisodeEntity();

            MergedEntity.AbsoluteNumber =
                (int)Util.CopyObject(Source.AbsoluteNumber, Destination.AbsoluteNumber, WriteMethod);
            MergedEntity.AirsAfterSeason =
                (int)Util.CopyObject(Source.AirsAfterSeason, Destination.AirsAfterSeason, WriteMethod);
            MergedEntity.AirsBeforeSeason =
                (int)Util.CopyObject(Source.AirsBeforeSeason, Destination.AirsBeforeSeason, WriteMethod);
            MergedEntity.Banner = MergeImageEntity(Source.Banner, Destination.Banner, WriteMethod);
            MergedEntity.SeasonBanner = MergeImageEntity(Source.SeasonBanner, Destination.SeasonBanner, WriteMethod);
            MergedEntity.Cast = MergePersonList(Source.Cast, Destination.Cast, WriteMethod, MergeOnPersonName);
            MergedEntity.DvdChapter = (int)Util.CopyObject(Source.DvdChapter, Destination.DvdChapter, WriteMethod);
            MergedEntity.DvdDiscID = (int)Util.CopyObject(Source.DvdDiscID, Destination.DvdDiscID, WriteMethod);
            MergedEntity.DvdEpisodeNumber =
                (double)Util.CopyObject(Source.DvdEpisodeNumber, Destination.DvdEpisodeNumber, WriteMethod);
            MergedEntity.DvdSeason = (int)Util.CopyObject(Source.DvdSeason, Destination.DvdSeason, WriteMethod);
            MergedEntity.EpisodeName =
                (string)Util.CopyObject(Source.EpisodeName, Destination.EpisodeName, WriteMethod);
            MergedEntity.EpisodeNumber =
                (int)Util.CopyObject(Source.EpisodeNumber, Destination.EpisodeNumber, WriteMethod);
            MergedEntity.FirstAired = (DateTime)Util.CopyObject(Source.FirstAired, Destination.FirstAired, WriteMethod);
            MergedEntity.IMDBID = (string)Util.CopyObject(Source.IMDBID, Destination.IMDBID, WriteMethod);
            MergedEntity.IsSpecial = (bool)Util.CopyObject(Source.IsSpecial, Destination.IsSpecial, WriteMethod);
            MergedEntity.Language = (string)Util.CopyObject(Source.Language, Destination.Language, WriteMethod);
            MergedEntity.Overview = (string)Util.CopyObject(Source.Overview, Destination.Overview, WriteMethod);
            MergedEntity.ProductionCode =
                (string)Util.CopyObject(Source.ProductionCode, Destination.ProductionCode, WriteMethod);
            MergedEntity.Rating = (double)Util.CopyObject(Source.Rating, Destination.Rating, WriteMethod);
            MergedEntity.SeasonID = (int)Util.CopyObject(Source.SeasonID, Destination.SeasonID, WriteMethod);
            MergedEntity.SeasonNumber =
                (int)Util.CopyObject(Source.SeasonNumber, Destination.SeasonNumber, WriteMethod);
            MergedEntity.SeriesID = (int)Util.CopyObject(Source.SeriesID, Destination.SeriesID, WriteMethod);
            MergedEntity.TvdbID = (int)Util.CopyObject(Source.TvdbID, Destination.TvdbID, WriteMethod);

            return MergedEntity;
        }

        public static IList<EpisodeEntity> MergeEpisodeList(IList<EpisodeEntity> Source,
                                                            IList<EpisodeEntity> Destination, MediaMergeType WriteMethod,
                                                            bool MergeOnPersonName)
        {
            if (Destination == null || Destination.Count == 0 || WriteMethod == MediaMergeType.OVERWRITE)
            {
                return Source;
            }
            if (Source == null || Source.Count == 0)
            {
                return Destination;
            }

            IList<EpisodeEntity> MergedEntity = new List<EpisodeEntity>();
            if (WriteMethod == MediaMergeType.COPY_NEW)
            {
                foreach (EpisodeEntity dEE in Destination)
                {
                    MergedEntity.Add(dEE);
                }
                foreach (EpisodeEntity sEE in Source)
                {
                    if (EpisodeExistsInList(MergedEntity, sEE) != null)
                    {
                        MergedEntity.Add(sEE);
                    }
                }

                return (MergedEntity);
            }

            if (WriteMethod == MediaMergeType.WRITE_IF_LARGER ||
                WriteMethod == MediaMergeType.WRITE_ONLY_ON_NULL_OR_EMPTY)
            {
                foreach (EpisodeEntity dEE in Destination)
                {
                    MergedEntity.Add(dEE);
                }
                foreach (EpisodeEntity sEE in Source)
                {
                    EpisodeEntity retVal = EpisodeExistsInList(MergedEntity, sEE);
                    if (retVal == null)
                    {
                        MergedEntity.Add(sEE);
                    }
                    else
                    {
                        MergedEntity.Add(MergeEpisodeEntity(sEE, retVal, WriteMethod, MergeOnPersonName));
                    }
                }
            }

            return MergedEntity;
        }

        public static FilmographyEntity MergeFilmographyEntity(FilmographyEntity Source, FilmographyEntity Destination,
                                                               MediaMergeType WriteMethod)
        {
            if (Destination == null || WriteMethod == MediaMergeType.OVERWRITE)
            {
                return Source;
            }

            if (Source == null)
            {
                return Destination;
            }
            var MergedEntity = new FilmographyEntity();
            MergedEntity.ID = (Guid)Util.CopyObject(Source.ID, Destination.ID, WriteMethod);
            MergedEntity.Character = (string)Util.CopyObject(Source.Character, Destination.Character, WriteMethod);
            MergedEntity.Department = (string)Util.CopyObject(Source.Department, Destination.Character, WriteMethod);
            MergedEntity.Job = (string)Util.CopyObject(Source.Job, Destination.Job, WriteMethod);
            MergedEntity.Url = (string)Util.CopyObject(Source.Url, Destination.Url, WriteMethod);

            return MergedEntity;
        }

        public static ImageEntity MergeImageEntity(ImageEntity Source, ImageEntity Destination,
                                                   MediaMergeType WriteMethod)
        {
            if (Destination == null || WriteMethod == MediaMergeType.OVERWRITE)
            {
                return Source;
            }

            if (Source == null)
            {
                return Destination;
            }

            // Images are special because they should represent an actual file on the machine
            // So we are going to actually see if the images are on the drive and see what is what

            bool SourceFileExists = false;
            bool DestinationFileExists = false;

            if (Source.Filename != null && File.Exists(Source.Filename))
            {
                SourceFileExists = true;
            }

            if (Destination.Filename != null && File.Exists(Destination.Filename))
            {
                DestinationFileExists = true;
            }

            if (!DestinationFileExists && SourceFileExists)
            {
                return Source;
            }

            if (!SourceFileExists && DestinationFileExists)
            {
                return Destination;
            }

            // We don't actually want to merge all the data because they represent a special item on the drive that has unique characteristics
            if (WriteMethod == MediaMergeType.WRITE_IF_LARGER)
            {
                if ((Source.Height * Source.Width) > (Destination.Height * Destination.Width))
                {
                    return Source;
                }
            }
            if (WriteMethod == MediaMergeType.WRITE_ONLY_ON_NULL_OR_EMPTY)
            {
                if (Destination.Height == 0 || Destination.Width == 0)
                {
                    return Source;
                }
            }

            return Destination;
        }

        public static IList<ImageEntity> MergeImageList(IList<ImageEntity> Source, IList<ImageEntity> Destination,
                                                        MediaMergeType WriteMethod)
        {
            if (Destination == null || Destination.Count == 0 || WriteMethod == MediaMergeType.OVERWRITE)
            {
                return Source;
            }
            if (Source == null || Source.Count == 0)
            {
                return Destination;
            }

            if (WriteMethod == MediaMergeType.COPY_NEW)
            {
                foreach (ImageEntity sIE in Source)
                {
                    if (!Destination.Contains(sIE))
                    {
                        Destination.Add(sIE);
                    }
                }
                return Destination;
            }
            if (WriteMethod == MediaMergeType.WRITE_IF_LARGER)
            {
                if (Source.Count > Destination.Count)
                {
                    return Source;
                }
                else
                {
                    return Destination;
                }
            }

            return Destination;
        }

        public static IList<DayOfWeek?> MergeListDayOfWeek(IList<DayOfWeek?> Source, IList<DayOfWeek?> Destination,
                                                           MediaMergeType WriteMethod)
        {
            if (Destination == null || WriteMethod == MediaMergeType.OVERWRITE)
            {
                return Source;
            }
            if (Source == null)
            {
                return Destination;
            }

            if (Source.Count > Destination.Count && WriteMethod == MediaMergeType.WRITE_IF_LARGER)
            {
                return Source;
            }

            if ((Destination == null || Destination.Count == 0) &&
                WriteMethod == MediaMergeType.WRITE_ONLY_ON_NULL_OR_EMPTY)
            {
                return Source;
            }

            IList<DayOfWeek?> MergedObject = new List<DayOfWeek?>();

            foreach (DayOfWeek dow in Source)
            {
                if (!MergedObject.Contains(dow))
                {
                    MergedObject.Add(dow);
                }
            }

            foreach (DayOfWeek dow in Destination)
            {
                if (WriteMethod == MediaMergeType.COPY_NEW)
                {
                    if (!MergedObject.Contains(dow))
                    {
                        MergedObject.Add(dow);
                    }
                }
            }
            return MergedObject;
        }

        public static IList<SimilarItemEntity> MergeSimiliarItems(Config config, IList<SimilarItemEntity> Source,
                                                                  IList<SimilarItemEntity> Destination,
                                                                  MediaMergeType WriteMethod)
        {
            if (Destination == null || WriteMethod == MediaMergeType.OVERWRITE)
            {
                return Source;
            }
            if (Source == null)
            {
                return Destination;
            }

            if (Source.Count > Destination.Count && WriteMethod == MediaMergeType.WRITE_IF_LARGER)
            {
                return Source;
            }
            if ((Destination == null || Destination.Count == 0) &&
                WriteMethod == MediaMergeType.WRITE_ONLY_ON_NULL_OR_EMPTY)
            {
                return Source;
            }

            IList<SimilarItemEntity> MergedObject = new List<SimilarItemEntity>();
            foreach (SimilarItemEntity sie in Source)
            {
                MergedObject.Add(sie);
            }

            foreach (SimilarItemEntity sie in Destination)
            {
                bool exists = false;
                foreach (SimilarItemEntity mSie in MergedObject)
                {
                    // Check to see if we have an identical ID *AND* the id's arent the default
                    if ((mSie.IMDBID == sie.IMDBID && (!String.IsNullOrWhiteSpace(mSie.IMDBID))) ||
                        (mSie.TMDBID == sie.TMDBID && mSie.TMDBID != 0) ||
                        (mSie.TVDBID == sie.TVDBID && mSie.TVDBID != 0))
                    {
                        exists = true;
                        break;
                    }
                    if (!exists)
                    {
                        MergedObject.Add(mSie);
                    }
                }
            }
            return MergedObject;
        }

        public static MediaClass MergeMediaObjects(Config config, MediaClass Source, MediaClass Destination,
                                                   MediaMergeType WriteMethod)
        {
            Logger logger = config.Logger;
            logger.Log("Entering Utilities.MediaUtil.MergeMediaObjects()");

            if (Destination == null || WriteMethod == MediaMergeType.OVERWRITE)
            {
                return Source;
            }
            if (Source == null)
            {
                return Destination;
            }

            var MergedObject = new MediaClass(config);
            MergedObject.Backdrop = MergeImageEntity(Source.Backdrop, Destination.Backdrop, WriteMethod);
            MergedObject.Poster = MergeImageEntity(Source.Poster, Destination.Poster, WriteMethod);

            MergedObject.SimilarItems = MergeSimiliarItems(config, Source.SimilarItems, Destination.SimilarItems,
                                                           WriteMethod);
            MergedObject.Adult = (bool)Util.CopyObject(Source.Adult, Destination.Adult, WriteMethod);
            MergedObject.AltName = (List<string>)Util.CopyObject(Source.AltName, Destination.AltName, WriteMethod);
            MergedObject.AudioBitrate =
                (int)Util.CopyObject(Source.AudioBitrate, Destination.AudioBitrate, WriteMethod);
            MergedObject.AudioChannels =
                (int)Util.CopyObject(Source.AudioChannels, Destination.AudioChannels, WriteMethod);
            MergedObject.AudioCodec = (string)Util.CopyObject(Source.AudioCodec, Destination.AudioCodec, WriteMethod);
            MergedObject.AudioCodecRaw =
                (string)Util.CopyObject(Source.AudioCodecRaw, Destination.AudioCodecRaw, WriteMethod);
            MergedObject.AudioFrequency =
                (long)Util.CopyObject(Source.AudioFrequency, Destination.AudioFrequency, WriteMethod);
            MergedObject.Budget = (string)Util.CopyObject(Source.Budget, Destination.Budget, WriteMethod);

            MergedObject.Cast = MergePersonList(Source.Cast, Destination.Cast, WriteMethod, config.MergeOnPersonName);
            MergedObject.Categories =
                (List<String>)Util.CopyObject(Source.Categories, Destination.Categories, WriteMethod);
            MergedObject.Certifications =
                MergeCertifications(Source.Certifications, Destination.Certifications, WriteMethod);
            MergedObject.ContentProtected =
                (bool)Util.CopyObject(Source.ContentProtected, Destination.ContentProtected, WriteMethod);
            MergedObject.Countries =
                (List<string>)Util.CopyObject(Source.Countries, Destination.Countries, WriteMethod);
            MergedObject.Description =
                (string)Util.CopyObject(Source.Description, Destination.Description, WriteMethod);
            MergedObject.Distributors =
                (List<string>)Util.CopyObject(Source.Distributors, Destination.Distributors, WriteMethod);
            MergedObject.DVDId = (string)Util.CopyObject(Source.DVDId, Destination.DVDId, WriteMethod);
            MergedObject.Episodes = MergeEpisodeList(Source.Episodes, Destination.Episodes, WriteMethod,
                                                     config.MergeOnPersonName);
            MergedObject.Filename = (string)Util.CopyObject(Source.Filename, Destination.Filename, WriteMethod);
            MergedObject.Genre = (List<string>)Util.CopyObject(Source.Genre, Destination.Genre, WriteMethod);
            MergedObject.Images = MergeImageList(Source.Images, Destination.Images, WriteMethod);
            MergedObject.IMDBID = (string)Util.CopyObject(Source.IMDBID, Destination.IMDBID, WriteMethod);
            MergedObject.IsDelay = (bool)Util.CopyObject(Source.IsDelay, Destination.IsDelay, WriteMethod);
            MergedObject.IsFinale = (bool)Util.CopyObject(Source.IsFinale, Destination.IsFinale, WriteMethod);
            MergedObject.IsHDContent = (bool)Util.CopyObject(Source.IsHDContent, Destination.IsHDContent, WriteMethod);
            MergedObject.IsLive = (bool)Util.CopyObject(Source.IsLive, Destination.IsLive, WriteMethod);
            MergedObject.IsMovie = (bool)Util.CopyObject(Source.IsMovie, Destination.IsMovie, WriteMethod);
            MergedObject.IsPremire = (bool)Util.CopyObject(Source.IsPremire, Destination.IsPremire, WriteMethod);
            MergedObject.IsRepeat = (bool)Util.CopyObject(Source.IsRepeat, Destination.IsRepeat, WriteMethod);
            MergedObject.IsSAP = (bool)Util.CopyObject(Source.IsSAP, Destination.IsSAP, WriteMethod);
            MergedObject.IsSport = (bool)Util.CopyObject(Source.IsSport, Destination.IsSport, WriteMethod);
            MergedObject.IsSubtitled = (bool)Util.CopyObject(Source.IsSubtitled, Destination.IsSubtitled, WriteMethod);
            MergedObject.IsTVSeries = (bool)Util.CopyObject(Source.IsTVSeries, Destination.IsTVSeries, WriteMethod);
            MergedObject.Languages =
                (List<string>)Util.CopyObject(Source.Languages, Destination.Languages, WriteMethod);
            MergedObject.LastModified =
                (DateTime?)Util.CopyObject(Source.LastModified, Destination.LastModified, WriteMethod);
            MergedObject.MediaType = (EMediaType)Util.CopyObject(Source.MediaType, Destination.MediaType, WriteMethod);
            MergedObject.Metadata = MergeMetadataList(Source.Metadata, Destination.Metadata, WriteMethod);
            MergedObject.MPAARating = (string)Util.CopyObject(Source.MPAARating, Destination.MPAARating, WriteMethod);
            MergedObject.Name = (string)Util.CopyObject(Source.Name, Destination.Name, WriteMethod);
            MergedObject.NetworkAffiliation =
                (string)Util.CopyObject(Source.NetworkAffiliation, Destination.NetworkAffiliation, WriteMethod);
            MergedObject.OriginalBroadcastTime =
                (DateTime?)Util.CopyObject(Source.OriginalBroadcastTime, Destination.OriginalBroadcastTime, WriteMethod);
            MergedObject.Overview = (string)Util.CopyObject(Source.Overview, Destination.Overview, WriteMethod);
            MergedObject.ParentalRating =
                (string)Util.CopyObject(Source.ParentalRating, Destination.ParentalRating, WriteMethod);
            MergedObject.Popularity = (double)Util.CopyObject(Source.Popularity, Destination.Popularity, WriteMethod);
            MergedObject.Rating = (double)Util.CopyObject(Source.Rating, Destination.Rating, WriteMethod);
            MergedObject.Released = (DateTime?)Util.CopyObject(Source.Released, Destination.Released, WriteMethod);
            MergedObject.Revenue = (string)Util.CopyObject(Source.Revenue, Destination.Revenue, WriteMethod);
            MergedObject.RottenTomatosID =
                (int)Util.CopyObject(Source.RottenTomatosID, Destination.RottenTomatosID, WriteMethod);
            MergedObject.RunTime = (TimeSpan)Util.CopyObject(Source.RunTime, Destination.RunTime, WriteMethod);
            MergedObject.Score = (double)Util.CopyObject(Source.Score, Destination.Score, WriteMethod);
            MergedObject.SeriesAirsDaysOfWeek = MergeListDayOfWeek(Source.SeriesAirsDaysOfWeek,
                                                                   Destination.SeriesAirsDaysOfWeek, WriteMethod);
            MergedObject.SeriesAirsTime =
                (DateTime?)Util.CopyObject(Source.SeriesAirsTime, Destination.SeriesAirsTime, WriteMethod);
            MergedObject.SeriesID = (int)Util.CopyObject(Source.SeriesID, Destination.SeriesID, WriteMethod);
            MergedObject.StationName =
                (string)Util.CopyObject(Source.StationName, Destination.StationName, WriteMethod);
            MergedObject.Studios = (IList<string>)Util.CopyObject(Source.Studios, Destination.Studios, WriteMethod);
            MergedObject.Subtitle = (string)Util.CopyObject(Source.Subtitle, Destination.Subtitle, WriteMethod);
            MergedObject.Title = (string)Util.CopyObject(Source.Title, Destination.Title, WriteMethod);
            MergedObject.TmdbID = (int)Util.CopyObject(Source.TmdbID, Destination.TmdbID, WriteMethod);
            MergedObject.Trailer = (string)Util.CopyObject(Source.Trailer, Destination.Trailer, WriteMethod);
            MergedObject.Translated = (bool)Util.CopyObject(Source.Translated, Destination.Translated, WriteMethod);
            MergedObject.TvdbID = (int)Util.CopyObject(Source.TvdbID, Destination.TvdbID, WriteMethod);
            MergedObject.URL = (string)Util.CopyObject(Source.URL, Destination.URL, WriteMethod);
            MergedObject.VideoAspect =
                (string)Util.CopyObject(Source.VideoAspect, Destination.VideoAspect, WriteMethod);
            MergedObject.VideoBitrate =
                (float)Util.CopyObject(Source.VideoBitrate, Destination.VideoBitrate, WriteMethod);
            MergedObject.VideoBitRateMode =
                (string)Util.CopyObject(Source.VideoBitRateMode, Destination.VideoBitRateMode, WriteMethod);
            MergedObject.VideoCodec = (string)Util.CopyObject(Source.VideoCodec, Destination.VideoCodec, WriteMethod);
            MergedObject.VideoCodecVersion =
                (string)Util.CopyObject(Source.VideoCodecVersion, Destination.VideoCodecVersion, WriteMethod);
            MergedObject.VideoFileSize =
                (long)Util.CopyObject(Source.VideoFileSize, Destination.VideoFileSize, WriteMethod);
            MergedObject.VideoFrameRate =
                (float)Util.CopyObject(Source.VideoFrameRate, Destination.VideoFrameRate, WriteMethod);
            MergedObject.VideoHeight = (int)Util.CopyObject(Source.VideoHeight, Destination.VideoHeight, WriteMethod);
            MergedObject.VideoLength =
                (TimeSpan)Util.CopyObject(Source.VideoLength, Destination.VideoLength, WriteMethod);
            MergedObject.VideoQuality =
                (string)Util.CopyObject(Source.VideoQuality, Destination.VideoQuality, WriteMethod);
            MergedObject.VideoWidth = (int)Util.CopyObject(Source.VideoWidth, Destination.VideoWidth, WriteMethod);

            return MergedObject;
        }

        public static MetadataEntity MergeMetadataEntity(MetadataEntity Source, MetadataEntity Destination,
                                                         MediaMergeType WriteMethod, Config config)
        {
            if (Destination == null || WriteMethod == MediaMergeType.OVERWRITE)
            {
                return Source;
            }
            if (Source == null)
            {
                return Destination;
            }

            var MergedEntity = new MetadataEntity();

            // We will assume they are the same at this point
            if (Source.Key != null)
            {
                MergedEntity.Key = Source.Key;
            }
            MergedEntity.Value = (string)Util.CopyObject(Source.Value, Destination.Value, WriteMethod);
            return MergedEntity;
        }

        public static IList<MetadataEntity> MergeMetadataList(IList<MetadataEntity> Source,
                                                              IList<MetadataEntity> Destination,
                                                              MediaMergeType WriteMethod)
        {
            if (Destination == null || WriteMethod == MediaMergeType.OVERWRITE)
            {
                return Source;
            }
            if (Source == null)
            {
                return Destination;
            }

            IList<MetadataEntity> MergedEntity = new List<MetadataEntity>();

            foreach (MetadataEntity mdE in Source)
            {
                MergedEntity.Add(mdE);
            }

            foreach (MetadataEntity mdE in Destination)
            {
                MetadataEntity searchMDE = MetadataListContains(mdE, MergedEntity);
                if (searchMDE != null)
                {
                    if (WriteMethod == MediaMergeType.WRITE_IF_LARGER)
                    {
                        if (searchMDE.Value != null && mdE.Value != null)
                        {
                            if (mdE.Value.Length > searchMDE.Value.Length)
                            {
                                MergedEntity.Remove(searchMDE);
                                MergedEntity.Add(mdE);
                            }
                        }
                        else
                        {
                            if (mdE.Value == null)
                            {
                                MergedEntity.Remove(searchMDE);
                                MergedEntity.Add(mdE);
                            }
                        }
                    }

                    if (WriteMethod == MediaMergeType.WRITE_ONLY_ON_NULL_OR_EMPTY)
                    {
                        if (searchMDE.Value == null || searchMDE.Value.Length == 0)
                        {
                            MergedEntity.Remove(searchMDE);
                            MergedEntity.Add(mdE);
                        }
                    }
                }
                else
                {
                    if (WriteMethod == MediaMergeType.COPY_NEW)
                    {
                        MergedEntity.Add(mdE);
                    }
                }
            }
            return MergedEntity;
        }

        public static IList<CertificationEntity> MergeCertifications(IList<CertificationEntity> Source,
                                                                     IList<CertificationEntity> Destination,
                                                                     MediaMergeType WriteMethod)
        {
            IList<CertificationEntity> mCertificationEntities = new List<CertificationEntity>();
            if (Destination == null || WriteMethod == MediaMergeType.OVERWRITE)
            {
                return Source;
            }

            if (Source == null)
            {
                return Destination;
            }

            if (Destination.Count == 0 && WriteMethod == MediaMergeType.WRITE_ONLY_ON_NULL_OR_EMPTY)
            {
                return Source;
            }

            if (Source.Count > Destination.Count && WriteMethod == MediaMergeType.WRITE_IF_LARGER)
            {
                return Source;
            }

            if (WriteMethod == MediaMergeType.COPY_NEW)
            {
                foreach (CertificationEntity dCE in Destination)
                {
                    mCertificationEntities.Add(dCE);
                }
                foreach (CertificationEntity sCE in Source)
                {
                    bool exists = false;
                    foreach (CertificationEntity dCE in mCertificationEntities)
                    {
                        if (sCE.CountryCode.Equals(dCE.CountryCode))
                        {
                            exists = true;
                            break;
                        }
                    }
                    if (!exists)
                    {
                        mCertificationEntities.Add(sCE);
                    }
                }

                return (mCertificationEntities);
            }

            return null;
        }

        public static PersonEntity MergePersonEntity(PersonEntity Source, PersonEntity Destination,
                                                     MediaMergeType WriteMethod, bool MergeOnPersonName)
        {
            if (Destination == null || WriteMethod == MediaMergeType.OVERWRITE)
            {
                return Source;
            }
            if (Source == null)
            {
                return Destination;
            }

            var MergedEntity = new PersonEntity();
            MergedEntity.ID = (Guid)Util.CopyObject(Source.ID, Destination.ID, WriteMethod);
            MergedEntity.AlsoKnownAs =
                (List<string>)Util.CopyObject(Source.AlsoKnownAs, Destination.AlsoKnownAs, WriteMethod);
            MergedEntity.BirthPlace = (string)Util.CopyObject(Source.BirthPlace, Destination.BirthPlace, WriteMethod);
            MergedEntity.Death = (DateTime)Util.CopyObject(Source.Death, Destination.Death, WriteMethod);
            MergedEntity.Department = (string)Util.CopyObject(Source.Department, Destination.Department, WriteMethod);
            MergedEntity.Filmography = new List<FilmographyEntity>();
            if (WriteMethod == MediaMergeType.COPY_NEW)
            {
                if (Destination.Filmography != null)
                {
                    foreach (FilmographyEntity dFE in Destination.Filmography)
                    {
                        MergedEntity.Filmography.Add(dFE);
                    }
                }
                foreach (FilmographyEntity sFE in Source.Filmography)
                {
                    if (!MergedEntity.Filmography.Contains(sFE))
                    {
                        MergedEntity.Filmography.Add(sFE);
                    }
                }
            }
            else
            {
                if (WriteMethod == MediaMergeType.WRITE_IF_LARGER)
                {
                    foreach (FilmographyEntity dFE in Destination.Filmography)
                    {
                        MergedEntity.Filmography.Add(dFE);
                    }
                    foreach (FilmographyEntity sFE in Source.Filmography)
                    {
                        if (Destination.Filmography.Contains(sFE))
                        {
                            // Do a copy per item
                            MergedEntity.Filmography.Add(MergeFilmographyEntity(sFE,
                                                                                Destination.Filmography[
                                                                                    Destination.Filmography.IndexOf(sFE)
                                                                                    ], WriteMethod));
                        }
                        else
                        {
                            MergedEntity.Filmography.Add(sFE);
                        }
                    }
                }
                else
                {
                    if (WriteMethod == MediaMergeType.WRITE_ONLY_ON_NULL_OR_EMPTY)
                    {
                        if (Destination.Filmography == null || Destination.Filmography.Count == 0)
                        {
                            foreach (FilmographyEntity sFE in Source.Filmography)
                            {
                                MergedEntity.Filmography.Add(sFE);
                            }
                        }
                        else
                        {
                            foreach (FilmographyEntity dFE in Destination.Filmography)
                            {
                                MergedEntity.Filmography.Add(dFE);
                            }
                        }
                    }
                }
            }

            MergedEntity.ID = (Guid)Util.CopyObject(Source.ID, Destination.ID, WriteMethod);
            MergedEntity.Image = MergeImageEntity(Source.Image, Destination.Image, WriteMethod);
            MergedEntity.Images = MergeImageList(Source.Images, Destination.Images, WriteMethod);
            MergedEntity.IMDBID = (string)Util.CopyObject(Source.IMDBID, Destination.IMDBID, WriteMethod);
            MergedEntity.Job = (List<string>)Util.CopyObject(Source.Job, Destination.Job, WriteMethod);
            MergedEntity.Name = (string)Util.CopyObject(Source.Name, Destination.Name, WriteMethod);
            MergedEntity.Nominations =
                (List<string>)Util.CopyObject(Source.Nominations, Destination.Nominations, WriteMethod);
            MergedEntity.ThumbURL = (string)Util.CopyObject(Source.ThumbURL, Destination.ThumbURL, WriteMethod);
            MergedEntity.TMDBID = (int)Util.CopyObject(Source.TMDBID, Destination.TMDBID, WriteMethod);
            MergedEntity.TVDBID = (int)Util.CopyObject(Source.TVDBID, Destination.TVDBID, WriteMethod);
            MergedEntity.URL = (string)Util.CopyObject(Source.URL, Destination.URL, WriteMethod);

            return MergedEntity;
        }

        /// <summary>
        ///     Merges a list of PersonEntities.  A duplicate will be defined by the same TMDBID or IMDBID
        /// </summary>
        /// <param name="Source"> </param>
        /// <param name="Destination"> </param>
        /// <param name="WriteMethod"> </param>
        /// <returns> </returns>
        public static IList<PersonEntity> MergePersonList(IList<PersonEntity> Source, IList<PersonEntity> Destination,
                                                          MediaMergeType WriteMethod, bool MergeOnPersonName)
        {
            if (Destination == null || Destination.Count == 0 || WriteMethod == MediaMergeType.OVERWRITE)
            {
                return Source;
            }
            if (Source == null || Source.Count == 0)
            {
                return Destination;
            }

            var MergedEntity = new List<PersonEntity>();
            if (WriteMethod == MediaMergeType.COPY_NEW)
            {
                foreach (PersonEntity dPE in Destination)
                {
                    MergedEntity.Add(dPE);
                }
                foreach (PersonEntity sPE in Source)
                {
                    if (PersonExistsInList(MergedEntity, sPE, MergeOnPersonName) != null)
                    {
                        MergedEntity.Add(sPE);
                    }
                }

                return (MergedEntity);
            }

            if (WriteMethod == MediaMergeType.WRITE_IF_LARGER ||
                WriteMethod == MediaMergeType.WRITE_ONLY_ON_NULL_OR_EMPTY)
            {
                foreach (PersonEntity dPE in Destination)
                {
                    MergedEntity.Add(dPE);
                }
                foreach (PersonEntity sPE in Source)
                {
                    PersonEntity retVal = PersonExistsInList(MergedEntity, sPE, MergeOnPersonName);
                    if (retVal == null)
                    {
                        MergedEntity.Add(sPE);
                    }
                    else
                    {
                        MergedEntity.Add(MergePersonEntity(sPE, retVal, WriteMethod, MergeOnPersonName));
                    }
                }
            }

            return MergedEntity;
        }

        public static MetadataEntity MetadataListContains(MetadataEntity Entity, IList<MetadataEntity> List)
        {
            foreach (MetadataEntity mdE in List)
            {
                if (mdE.Key.Equals(Entity.Key))
                {
                    return mdE;
                }
            }

            return null;
        }

        /// <summary>
        ///     Checks to see if a episode exists in a list of episodes
        ///     Returns false if either are null or Episode = null or default values
        /// </summary>
        /// <param name="EpisodeList"> </param>
        /// <param name="Episode"> </param>
        /// <returns> </returns>
        public static EpisodeEntity EpisodeExistsInList(IList<EpisodeEntity> EpisodeList, EpisodeEntity Episode)
        {
            if (EpisodeList == null)
            {
                return null;
            }

            if (Episode == null)
            {
                return null;
            }

            if (Episode.TvdbID == 0 && Episode.SeriesID == 0)
            {
                return null;
            }

            foreach (EpisodeEntity ee in EpisodeList)
            {
                if (ee.TvdbID == Episode.TvdbID ||
                    ((ee.SeasonID == Episode.SeasonID && ee.SeasonID != 0) &&
                     (ee.EpisodeNumber == Episode.EpisodeNumber && ee.EpisodeNumber != 0)))
                {
                    return ee;
                }
            }

            return null;
        }

        /// <summary>
        ///     Checks to see if a person exists in a list of people
        ///     Returns false if either are null or Person = null or default values
        /// </summary>
        /// <param name="PersonList"> </param>
        /// <param name="Person"> </param>
        /// <returns> </returns>
        public static PersonEntity PersonExistsInList(IList<PersonEntity> PersonList, PersonEntity Person,
                                                      bool MergeOnPersonName)
        {
            if (PersonList == null)
            {
                return null;
            }

            if (Person == null)
            {
                return null;
            }

            if (Person.IMDBID == null && Person.TMDBID == 0)
            {
                return null;
            }

            foreach (PersonEntity pe in PersonList)
            {
                if (MergeOnPersonName)
                {
                    if (pe.TMDBID == Person.TMDBID || pe.IMDBID.ToUpper().Equals(Person.IMDBID.ToUpper()) ||
                        pe.Name.ToUpper() == Person.Name.ToUpper())
                    {
                        return pe;
                    }
                }

                if (pe.TMDBID == Person.TMDBID || pe.IMDBID.ToUpper().Equals(Person.IMDBID.ToUpper()))
                {
                    return pe;
                }
            }

            return null;
        }

        #endregion Methods
    }
}